function Observer(data) {
    //在Observer实例上暂存data
    this.data = data;
    //调用walk方法
    this.walk(data);
}

Observer.prototype = {
    walk: function(data) {
        //保存this  ==> Observe实例
        var me = this;
        //取出当前data中所有的key值,然后遍历
        Object.keys(data).forEach(function(key) {
            //调用实例的convert方法 传递过去当前属性的属性名和值
            me.convert(key, data[key]);
        });
    },
    convert: function(key, val) {
        //在vm.data对象上, 为每一个属性都增加响应式效果
        this.defineReactive(this.data, key, val);
    },

    defineReactive: function(data, key, val) {
        //为data中所有层次的属性都创建一个dep实例 =>{id:0 subs:[]}
        var dep = new Dep();
        //递归遍历data中所有层此的属性
        var childObj = observe(val);
        //为vm.data所有属性新增set和get方法(数据劫持)
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            get: function() {
                //判断Dep.target是否存在
                //如果后续有别的地方去触发了对当前数据的读操作,那么要确保不会再重复建立dep和wathcer的关系
                if (Dep.target) {//相关的watcher
                    //如果当前dep相关的watcher存在,那么执行dep上面的depend方法
                    dep.depend();
                }
                return val;
            },
            set: function(newVal) {
                //当vm.data.xxx被重新赋值的时候 会触发这个set方法
                if (newVal === val) {//判断新值和旧值是否一直 如果一直就不去做任何的操作
                    return;
                }
                //代码执行到这个位置的时候,vm.data中的数据已经是最新的了,但是页面还没有更新
                val = newVal;//如果不一致就把旧的val更新成最新的
                // 如果新增加的值是object类型的话，需要重新进行数据劫持和监听
                childObj = observe(newVal);
                // 通知订阅者
                dep.notify();
            }
        });
    }
};

function observe(value, vm) {
    //判断value是否存在或者value的数据类型是否为一个object(递归循环的终止条件)
    if (!value || typeof value !== 'object') {
        return;
    }

    //声明一个Observer实例 把value传递过去
    return new Observer(value);
};


var uid = 0;

function Dep() {
    //每创建一个dep实例都会给这个dep增加一个唯一标识
    this.id = uid++;
    //sub订阅 s  ==> 里面放了很多个watcher的实例
    this.subs = [];
}
/* dep实例的样子
let d = {
    id: 0,
    subs: [
       {//watcher
            cb: function(){},
            vm: vm,
            exp: "a",
            depIds: {},//js存数据 要么就是[] 要么就是{}
            value: ""
        },
       //watcher....
    ]
}*/

Dep.prototype = {
    //在当前dep的subs中添加相关的watcher
    addSub: function(sub) {
        //this ==> dep
        //dep已经和相关的watcher建立了关系
        this.subs.push(sub);
    },

    //建立dep和watcher之间关系的开始
    depend: function() {
        //this ===> Dep的实例 dep
        //Dep.target ===> 相关的watcher
        Dep.target.addDep(this);
    },

    removeSub: function(sub) {
        var index = this.subs.indexOf(sub);
        if (index != -1) {
            this.subs.splice(index, 1);
        }
    },

    //通知所有订阅者
    notify: function() {
        //循环遍历当前所有的订阅者(watcher), 调用watcher的update方法
        this.subs.forEach(function(sub) {
            sub.update();
        });
    }
};

Dep.target = null;